package com.wn.config;

import com.wn.realm.MyRealm;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author yellow Docter
 * @date 2022 -05-16
 * @desc
 *
 *  shiro 整合 springboot 的配置
 *
 *  00 如果 进行了加密的认证 需要配置 加密算法
 *  01  shiro的Realm
 *  02  shiro的SecurityManager
 *  03 过滤器器 shiroFilter
 *
 */
//@Configuration
public class ShiroConfig {

    /**
     * 0、创建密码匹配器，指定加密算法
     */
    @Bean
    public CredentialsMatcher credentialsMatcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        // 指定加密算法
        matcher.setHashAlgorithmName("md5");
        // 迭代次数
        matcher.setHashIterations(3);
        return matcher;
    }


    /**
     * 01  shiro的Realm
     */
    @Bean
    public MyRealm myRealm(CredentialsMatcher credentialsMatcher){

        MyRealm myRealm = new MyRealm();

        // realm 配置加密器
        myRealm.setCredentialsMatcher(credentialsMatcher);

        return myRealm;
    }

    /**
     * 02 安全管理器
     * @return
     */
    @Bean
    public SecurityManager securityManager(MyRealm myRealm){

        //创建安全管理器
        // SecurityManager 是接口 有多个实现类
        //DefaultWebSecurityManager  web项目的安全管理器 可以直接使用
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        defaultWebSecurityManager.setRealm(myRealm);
        return defaultWebSecurityManager;

    }

    /**
     * ShiroFilterFactoryBean  过滤器工厂 可以管理 shiro封装的 shiroFilter
     *
     * shiro封装的filter 有很多
     *
     * anon       不能拦截 匿名就可以 进行方位资源
     * authc      需要拦截 授权才可以访问
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){

        //创建一个 bean
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();

        //设置安全管理器
        factoryBean.setSecurityManager(securityManager);

        // 页面跳转的配置
        // 如果没有认证  直接跳转到这个页面
        factoryBean.setLoginUrl("/login.html");
        //没有设置拦截规则

        Map<String,String> map = new HashMap<>();

        //整合的 时候  shiro 会把 静态资源进行拦截

        //把静态资源放行
        map.put("/css/**","anon");
        map.put("/img/**","anon");
        map.put("/js/**","anon");
        map.put("/pages/**","anon");
        map.put("/plugins/**","anon");
        map.put("/test/**","anon");

        // anon 匿名访问过滤器，指定不需要进行认证的资源
        map.put("/login","anon");
        map.put("/login.html","anon");
        // authc 认证过滤器； 访问/**所有资源都需要认证，除了放行的。
        map.put("/**","authc");

        factoryBean.setFilterChainDefinitionMap(map);

        return factoryBean;
    }

    /**
     * 4、开启权限校验注解支持
     */
    //5.1 开启Aop自动代理
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator proxy =
                new DefaultAdvisorAutoProxyCreator();
        // 设置true表示使用子类代理
        proxy.setProxyTargetClass(true);
        return proxy;
    }

    //5.2 匹配所有加了权限注解的方法，让权限校验注解生效。注入SecurityManager
    @Bean
    public AuthorizationAttributeSourceAdvisor advisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor =
                new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}
